#ifndef __HIKARI__NAVMESHMANAGER__
#define __HIKARI__NAVMESHMANAGER__

#include <vector>
#include <FileSection.h>
#include "astar.h"
#include "astarPointer.h"
#include "astarlocalpath.h"
#include "priorityqueueimpl.h"
#include "localsearcher.h"
#include<irrlicht.h>
#include "astardata.h"
using namespace std;
using namespace stdext;

class MapSearchNode
{
public:
        unsigned int x;
        unsigned int y;
		NavmeshRegion*currentRegion;
		MapSearchNode() { x = y = 0; currentRegion=NULL;}
		MapSearchNode( unsigned int px, unsigned int py, NavmeshRegion*currentRegion) {
			x=px; y=py; this->currentRegion=currentRegion;
		}

        float GoalDistanceEstimate( MapSearchNode &nodeGoal );
        bool IsGoal( MapSearchNode &nodeGoal );
        bool GetSuccessors( AStarSearch<MapSearchNode> *astarsearch, MapSearchNode *parent_node );
        float GetCost( MapSearchNode &successor );
        bool IsSameState( MapSearchNode &rhs );
};

class PathSmoother{
private:
	NavmeshRegion*polygon;
    vector<Point>*path;

	bool isWalkable(int index1, int index2);
public:
	PathSmoother(NavmeshRegion*polygon, vector<Point>*path){
		this->polygon=polygon;
		this->path=path;
	}

	vector<Point> smooth();
};
class NavmeshManager;

class NavmeshPath{
private:
	NavmeshManager*navmeshManager;
	int passedPointIndex;
	vector<NavmeshRegion*>regionsPath;
	vector<vector3df>pointsInCurrentSection;
	vector<Point>pointsIndexInCurrentSection;
	NavmeshRegion*currentRegion;
	FPoint startPoint;
	FPoint endPoint;
	
	bool initialized;
	int passedRegionIndex;
	bool recalculateLocalPath();
	Point startLocalPoint;
	Point endLocalPoint;
	
public:
	NavmeshPath(NavmeshManager*navmeshManager){
		this->navmeshManager=navmeshManager;
		initialized=false;
		passedRegionIndex=0;
		passedPointIndex=0;
	}

	

	bool getInitialized(){
		return initialized;
	}

	~NavmeshPath(){
		pointsInCurrentSection.clear();
	}
	
	bool nextPathPoint(vector3df&newPosition, float speed);
	bool nextPathPoint(vector3df&newPosition, float speed, bool first);

	vector<NavmeshRegion*>&getRegionsPath(){
		return regionsPath;
	}

	vector<vector3df>&getPointsInCurrentSection(){
		return pointsInCurrentSection;
	}

	vector<Point>&getPointsIndexInCurrentSection(){
		return pointsIndexInCurrentSection;
	}

	NavmeshRegion*getCurrentRegion(){
		return currentRegion;
	}

	void setCurrentRegion(NavmeshRegion*currentRegion){
		this->currentRegion=currentRegion;
	}

	FPoint&getStartPoint(){
		return startPoint;
	}

	FPoint&getEndPoint(){
		return endPoint;
	}

	Point&getStartLocalPoint(){
		return startLocalPoint;
	}

	Point&getEndLocalPoint(){
		return endLocalPoint;
	}
};

class NavmeshManager{
private:
	vector<NavmeshRegion*>regions;
	void removeDuplicatedConnectedCells();
	///For debug purpose
	vector3df*drawLocalStart;
	vector3df*drawLocalEnd;
	float cellWidthHeight;

public:

	void setStartDrawPoint(vector3df*startPoint){
		drawLocalStart=startPoint;
	}

	void setEndDrawPoint(vector3df*endPoint){
		drawLocalEnd=endPoint;
	}

	void setCellWidthHeight(float size){
		this->cellWidthHeight=size;
	}

	NavmeshManager(){
		drawLocalStart=NULL;
		drawLocalEnd=NULL;
	}
	NavmeshRegion*getRegion(float x, float y);

	vector<NavmeshRegion*>&getRegions(){
		return regions;
	}

	void clearNavmeshInfo();

	void load(FileSection*section);
	NavmeshPath*generatePath(vector3df&startPosition, vector3df&endPosition);
	void drawNavmesh(irr::video::IVideoDriver*driver);
	void unload();
};

#endif